home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Tool Chest / Networking / Network Watch (DMZ) v1.3 / dMZAT.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-16  |  29.8 KB  |  1,198 lines  |  [TEXT/MPS ]

  1. /*
  2. #-------------------------------------------------------------------------------------------
  3. #
  4. #    Program:    < DMZ 1.3 >
  5. #    File:        < dmzAT.c >
  6. #    
  7. #    by Pete Helme
  8. #    of <Apple Macintosh Developer Technical Support - or wheverever>
  9. #
  10. #    Modification History
  11. #    5/23/94     rrk    Implemented Steve Falkenburg's changes for compatibility with PPC
  12. #                    This code was compile with MPW 3.3.1 and Think C 7.0 using
  13. #                    Universal headers
  14. #    9/20/92  rrk    Change nbp type from "\pnot Anything" to "\pEcho Type".  Set socket
  15. #                    address to 4 as opposed to leaving it at 0.
  16. #    3/25/92     rrk     Fixed program so that if no zones are selected and the "no zones (*)"
  17. #                    item selected, the local zone is searched.
  18. #    3/25/92     rrk     Implemented J. Luther's socket listener, replacing Pete's listener
  19. #    3/25/92  rrk    Updated code to work with Think C 5.0.
  20. #
  21. #    Copyright © 1990 Apple Computer, Inc.
  22. #    All rights reserved.
  23. #    
  24. #-------------------------------------------------------------------------------------------
  25. */
  26.  
  27. /*
  28.  *     dmz Sample AppleTalk Stuff
  29.  *
  30.  *    This unit handles all AppleTalk functions for dmz.  Including: AppleTalk 
  31.  *    presence verification and activation, socket opening, set self send enabling  
  32.  *    name binding protocol registration, bridge presence verification, 
  33.  *    zone name lookups, hot dish zapper, name removal, socket closing & no weeds.
  34.  *
  35.  */
  36.  
  37. #include    "dmz.h"
  38.  
  39.  
  40. /* globals from afar */
  41. /* out main dialog */
  42. extern DialogPtr     gLookupDialog;
  43. extern DialogPtr     gMyDialog;
  44. extern char         gNameGlob[34];
  45. extern SysEnvRec    GMAC;
  46. extern myATQEntry    gATQEntry;
  47. extern short        gATalkFlags;
  48.  
  49. /* and others */
  50. /* 
  51.  *     gBuffers is used in the by the socket listener code set up in the doEcho 
  52.  *     function.  The socket listener uses these buffers to save received packets
  53.  *    until they can be processed.
  54.  */
  55. PacketBuffer    gBuffers[kNumBuffers];    /* set up by InitEchoBuffers */
  56.  
  57. /* 
  58.  *     gFreeQ and gUsedQ as their names imply, are used to track whether gBuffers 
  59.  *  packet record buffers are available for use or have been filled in by the 
  60.  *  socket listener and are available for processing.
  61.  */
  62. static QHdr        gFreeQ, gUsedQ;        /* set up by InitEchoBuffers */
  63. static Handle     gSockCodeHndl = nil;         /* handle to socket listener code resource */
  64.  
  65.  
  66. Ptr                 gBuffPtr = nil;
  67. myMPPParamBlock     *gPBLkUP = nil;
  68. Boolean             gUpdateListFlag;
  69. Boolean             gLookupFinished;
  70. NamesTableEntry     gMyNTE;
  71. AddrBlock             gTheBridgeAddress;
  72. Boolean                gHasPhase2 = false;
  73. NamesTableEntry     gLookupNTE;    
  74. char                gOrigSelfSend;
  75.  
  76. Ptr                    GTHEVBLPTR;
  77. Ptr                    GTHETASKPTR;
  78.  
  79. /*     
  80.  *    Inline routines for saving & restoring A5 in our PLookupName completion routine.
  81.  *
  82.  *    move.l    a5, -(a7)
  83.  *    move.l    $FFFC(a0), a5    ; -4(A0)
  84.  *
  85.  */
  86. #ifndef powerc
  87. pascal void saveThatA5(void)
  88.     = {0x2f0d, 0x2a68, 0xFFFC};
  89. #endif
  90.     
  91. /*
  92.  *    move.l    (a7)+, a5
  93.  */
  94. #ifndef powerc
  95. pascal void restoreThatA5(void)
  96.     = {0x2A5F};
  97. #endif
  98.     
  99.     
  100. /*     
  101.  *    Boring Pascal string concat routine.  Skip ahead a bit.
  102.  */
  103. unsigned char *Pstrcat(unsigned char *s, unsigned char *t)
  104. {
  105.     long     i, length;
  106.     unsigned char     *p;
  107.     
  108.     length = *t;
  109.     p = s + *s + 1;
  110.     t++;
  111.     
  112.     for(i=0;i<length;i++) 
  113.         *p++ = *t++;
  114.  
  115.     *s += length;
  116.     return s;
  117. }
  118.  
  119. /*     
  120.  *    Returns length of pascal type strings.  Again, quite boring.
  121.  */
  122. unsigned char PStrLen(unsigned char *e)
  123. {
  124.     unsigned char length;
  125.     
  126.     length = *e;
  127.     return(length);
  128. }
  129.  
  130. /*
  131.  * Returns true if two Pascal strings are the same, false otherwise.
  132.  */
  133.  
  134. Boolean    PStrComp(unsigned char *str1, unsigned char *str2)
  135.  
  136. {
  137.     unsigned char    i;
  138.     unsigned char    j;
  139.     Boolean            ok;
  140.     
  141.     if (*str1 != *str2)
  142.         return(false);                    /* strings are of unequal length */
  143.     
  144.     i = *str1;
  145.     ok = true;                            /* assume strings are the same */
  146.     j = 0;
  147.     for (j = 0; j < i; j++) {
  148.         if (*(++str1) != *(++str2))
  149.             return(false);
  150.     }
  151.     return(true);
  152. }        
  153.  
  154. /*     
  155.  *     Removes a specific NBP Lookup from queue if one pending.  Why?  So we don't hurt ourselves.
  156.  *    
  157.  */
  158. void killLookups(void)
  159. {
  160.     MPPParamBlock     killPB;
  161.     OSErr             resultCode;
  162.  
  163.     if(gPBLkUP->myMPP.MPPioResult == 1) {
  164.         killPB.NBPnKillQEl = (Ptr)&gPBLkUP->myMPP.MPP.qLink;
  165.         resultCode = PKillNBP(&killPB, false);
  166.         }
  167. }
  168.  
  169. /*     
  170.  *    Removes our name and ATP socket.
  171.  */
  172. void removeMyNameAndSocket(void)
  173. {
  174.     MPPParamBlock     pb;
  175.  
  176.     if (gATalkFlags & (1 << kNameRegistered)) {    
  177.         pb.NBPentityPtr = (Ptr)&gMyNTE.nt.entityData[0];
  178.         PRemoveName(&pb, false);
  179.         gATalkFlags &= (-1 ^ (1 << kNameRegistered));
  180.     }
  181.     
  182. }
  183.  
  184. /*     
  185.  *    Shutdown our AppleTalk usage.  Disposes of name lookup buffers.  
  186.  *    Calls to remove our NBP name.    
  187.  */
  188. void closeUpOurAppleTalk(void)
  189. {
  190.     Size        listenerSize;
  191.     
  192.     killLookups();
  193.     
  194.     if(gBuffPtr != 0L)
  195.         DisposPtr(gBuffPtr);
  196.     if(gPBLkUP != 0L)
  197.         DisposPtr((Ptr) gPBLkUP);
  198.  
  199.     if (gATalkFlags & (1 << kSocketBuffsHeld))    { /* ckeck if socket buffer held due to VM */
  200.         UnholdMemory(&gBuffers, sizeof(gBuffers));
  201.         UnholdMemory(&gFreeQ, sizeof(QHdr));
  202.         UnholdMemory(&gUsedQ, sizeof(QHdr));
  203.         gATalkFlags &= (-1 ^ (1 << kSocketBuffsHeld));
  204.     }
  205.  
  206.     if (gATalkFlags & (1 << kListenerHeld)) /* ckeck if socket listener held due to VM */
  207.     {
  208.         listenerSize = GetHandleSize(gSockCodeHndl);
  209.         UnholdMemory(*gSockCodeHndl, listenerSize);
  210.         gATalkFlags &= (-1 ^ (1 << kListenerHeld));
  211.     }        
  212.  
  213.     if (gATalkFlags & (1 << kATQInstalled))        /* check if ATalk Trans queue installed */
  214.     {
  215.         LAPRmvATQ((ATQEntry*)&gATQEntry);
  216.         gATalkFlags &= (-1 ^ (1 << kATQInstalled));
  217.     }
  218.  
  219.     removeMyNameAndSocket();
  220. }
  221.     
  222. /*     
  223.  *    Registers name from the System's STR -16413, the Flagship (Macintosh Name) resource under
  224.      System 7.x (what appears in the Sharing Setup control panel), or STR -16096 resource if 
  225.      under System 6.0.x. (what is usually seen in the Chooser) 
  226.  */
  227.  
  228. void registerMyName()
  229. {
  230.     MPPParamBlock     pb;
  231.     OSErr             err;
  232.     long             byteCount;
  233.     StringHandle    userName;
  234.     
  235.     byteCount = 0L;
  236.  
  237.     /* this grabs the name from the Macintosh Name String if it is found under System 7.x
  238.        or the user's Chooser name string if 6.0.x or earlier.  If there is nothing
  239.     there we'll substitute our own name */
  240.     userName = GetString(kFlagshipNameResourceID);
  241.     if (**userName == 0) 
  242.     {
  243.         userName = GetString(kMachineNameResourceID); 
  244.         if(**userName == 0)
  245.             BlockMove("\pYour name here.", *userName, 15L);
  246.     }
  247.  
  248.     NBPSetNTE((Ptr)&gMyNTE, (Ptr)*userName, (char *)kEchoType, (char *)"\p*", gMyNTE.nt.nteAddress.aSocket);
  249.  
  250.     pb.NBPinterval = 2;
  251.     pb.NBPcount = 3;
  252.  
  253.     /* wants pointer to NamesTableEntry NOT entityName! */
  254.     pb.NBP.NBPPtrs.ntQElPtr = (Ptr)&gMyNTE;
  255.     pb.NBPverifyFlag = 1; /* verify that we be the only one! */
  256.  
  257.     err = PRegisterName(&pb, false);
  258.     if (err == noErr) {
  259.         gATalkFlags |= (1 << kNameRegistered);
  260.         ((dmzEntryPtr) *(gATQEntry.globs))->dmzNTEPtr = &gMyNTE;
  261.     }
  262.     /* if error occured registering name, there is no reason to 
  263.      * abort the program 
  264.      */
  265.     
  266. }
  267.  
  268.     
  269. /* 
  270.  *    Enables AppleTalk option to talk to one's own node. ONLY for SE's, //'s or MacPluses with AppleTalk driver of v48 or greater!! 
  271.  *  Saves original state in the global gOrigSelfSend.
  272.  */
  273. void enableSetSelfSend() 
  274. {
  275.  
  276.     SetSelfparms    pb;
  277.     OSErr             err;
  278.  
  279.     pb.newSelfFlag = true;  /* set self send option */
  280.     err = PSetSelfSend((MPPPBPtr) &pb, false);
  281.     if (err == noErr)
  282.         gOrigSelfSend = pb.oldSelfFlag;
  283. }
  284.     
  285.  
  286. /* 
  287.  *    restores AppleTalk option to talk to one's own node. ONLY for SE's, //'s or MacPluses with AppleTalk driver of v48 or greater!! 
  288.  *  uses value in the global gOrigSelfSend.
  289.  */
  290. void restoreSetSelfSend() 
  291. {
  292.  
  293.     SetSelfparms    pb;
  294.  
  295.     pb.newSelfFlag = gOrigSelfSend;  /* set self send option to saved value*/
  296.     PSetSelfSend((MPPPBPtr) &pb, false);
  297. }
  298.     
  299.  
  300. /*    
  301.  *    Checks to see if we are running AppleTalk Phase 2 compatible drivers.
  302.  */
  303. void phase2Check()
  304. {
  305.     if(GMAC.atDrvrVersNum >= 53) 
  306.         gHasPhase2 = true;
  307.     else 
  308.         HideDItem(gLookupDialog, kPhase2Item);
  309. }
  310.  
  311.  
  312. /*    
  313.  *    Opens up AppleTalk.  Opens our ATP socket.  Initializes our flag
  314.  *  which indicate the current state of AppleTalk.  If AppleTalk is not
  315.  *  open, then we do not want to display the zone list.
  316.  */
  317. void InitAppleTalkVars()
  318. {
  319.     extern void     getTheZoneList();
  320.     OSErr            err;
  321.     
  322.     /* 
  323.      *    buffer necessary for async name lookups 
  324.      *  this routine can be called from the TransQueue
  325.      */
  326.     if (gPBLkUP == nil)
  327.         gPBLkUP = (myMPPParamBlock *) NewPtr(sizeof(myMPPParamBlock));
  328.     if (gBuffPtr == nil)
  329.         gBuffPtr = NewPtr(kLookupBufSize);
  330.     gMyNTE.nt.nteAddress.aSocket = kEchoSocket;
  331.     
  332.     if ((gPBLkUP == nil) || (gBuffPtr == nil))
  333.         BigBadError("\pError allocating lookup memory - Aborting program");
  334.     else
  335.     {
  336.         if (IsMPPOpen())
  337.         {
  338.             ((dmzEntryPtr) *(gATQEntry.globs))->atalkActive = true;
  339.             ((dmzEntryPtr) *(gATQEntry.globs))->atalkStatusChanged = false;
  340.             ((dmzEntryPtr) *(gATQEntry.globs))->dmzNTEPtr = nil;
  341.             phase2Check();
  342.             enableSetSelfSend();
  343.             getTheZoneList();        
  344.             registerMyName();
  345.         
  346.             /* call socket listener init code */
  347.             err = InitEchoBuffers();
  348.             if (err != noErr)
  349.             {
  350.                 BigBadError("\pError initializing Echo Buffers");
  351.             }
  352.         }
  353.         else
  354.         {
  355.             ((dmzEntryPtr) *(gATQEntry.globs))->atalkActive = false;
  356.             ((dmzEntryPtr) *(gATQEntry.globs))->atalkStatusChanged = false;
  357.             ((dmzEntryPtr) *(gATQEntry.globs))->dmzNTEPtr = nil;
  358.             tellUserNoZones();        // which tells the user that AppleTalk is off
  359.         }
  360.         
  361.     }
  362. }
  363.         
  364.  
  365.  
  366. /*
  367.  *    in order for us to use the standard qsort() algorithm, our data must be alligned in
  368.  *    an orderly fashion with a set offset from each data entry. This routine takes care of
  369.  *    that through simple _BlockMove manipulations.
  370.  */
  371. void addToUnpackedBuffer(Ptr oldBuffer, Ptr newBuffer, short numGot, short total)
  372. {
  373.     long    oldIndex = 0L, newIndex = 0L;
  374.     short    i;
  375.     
  376.     for(i=0;i<numGot;i++) {
  377.         BlockMove((Ptr)oldBuffer+oldIndex, (Ptr)newBuffer+(newIndex+total)*33, 33L);
  378.         oldIndex += (char)((Ptr)oldBuffer+oldIndex)[0]+1L;
  379.         newIndex += 1;
  380.         }
  381. }
  382.  
  383.  
  384. /*
  385.  *    return our local zone name the old fashioned way.  We could easily use the 
  386.  *  GetMyZone function, which would be simpler
  387.  */
  388. void getMyZone(char *myZoneBuffer)
  389. {
  390.     BDSElement         myZoneBDS;
  391.     ATPParamBlock     ZonePB;
  392.     
  393.     myZoneBDS.buffSize = 33;
  394.     myZoneBDS.buffPtr = (Ptr) myZoneBuffer;
  395.     myZoneBDS.dataSize = 0;
  396.     myZoneBDS.userBytes = 0;
  397.  
  398.     ZonePB.ATPatpFlags = 0;
  399.     ZonePB.ATPioCompletion = 0L; 
  400.     ZonePB.ATPuserData = 0;    /* ATP user data */
  401.     ZonePB.ATPaddrBlock = gTheBridgeAddress;
  402.     ZonePB.ATPreqLength = 0;
  403.     ZonePB.ATPreqPointer = 0L;
  404.     ZonePB.ATPbdsPointer = (Ptr)&myZoneBDS;
  405.     ZonePB.ATPnumOfBuffs = 1;
  406.     ZonePB.ATPtimeOutVal = 3;
  407.     ZonePB.ATPretryCount = 3;
  408.  
  409.     /*
  410.      *    make sure to NIL this field out so bottom three bytes are 0
  411.      */
  412.     ZonePB.ATPuserData = 0x07000000;        /* GetLocalZone = 7 */
  413.         
  414.     if(PSendRequest(&ZonePB, false) != noErr)
  415.         myZoneBuffer[0] = 0;
  416. }
  417.  
  418.  
  419. void doGetZoneListPrePh2()
  420. {            
  421.     BDSElement             myZoneBDS;
  422.     ATPParamBlock         ZonePB;
  423.     OSErr                 theResult;
  424.     long                 tempUserData;
  425.     Ptr                 theBufferPtr;
  426.     short                 zIndex, zoneCallType;
  427.     short                 NumZonesGot = 0, totalZones = 0;
  428.     Boolean             DontGetMoreZones;
  429.     extern ListHandle    zonesList;
  430.     Ptr                    returnBuffer;
  431.     
  432.     zIndex = 1;
  433.     zoneCallType = _GetZoneList;
  434.     DontGetMoreZones = false;
  435.     
  436.     returnBuffer = NewPtr(33*255); /* size of maxstring size * 255 zones */
  437.     
  438.     theBufferPtr = NewPtr(578); /* size of BDS */
  439.     if(MemError()==noErr) {
  440.         while(!DontGetMoreZones) {
  441.             zIndex += NumZonesGot;            /* index count. 1 for start */
  442.             myZoneBDS.buffSize = 578;
  443.             myZoneBDS.buffPtr = theBufferPtr;
  444.             myZoneBDS.dataSize = 0;
  445.             myZoneBDS.userBytes = 0;
  446.     
  447.             ZonePB.ATPatpFlags = 0;
  448.             ZonePB.ATPioCompletion = 0L; 
  449.             ZonePB.ATPuserData = 0;    /* ATP user data */
  450.             ZonePB.ATPaddrBlock = gTheBridgeAddress;
  451.             ZonePB.ATPreqLength = 0;
  452.             ZonePB.ATPreqPointer = 0L;
  453.             ZonePB.ATPbdsPointer = (Ptr)&myZoneBDS;
  454.             ZonePB.ATPnumOfBuffs = 1;
  455.             ZonePB.ATPtimeOutVal = 4;
  456.             ZonePB.ATPretryCount = 4;
  457.             
  458.             BlockMove((Ptr) &zoneCallType + 1, (Ptr) &tempUserData, 1L);
  459.             BlockMove((Ptr) &zIndex, (Ptr)&tempUserData + 2, 2L);
  460.     
  461.             ZonePB.ATPuserData = tempUserData;
  462.                 
  463.             theResult = PSendRequest(&ZonePB, false);
  464.     
  465.             if(theResult == noErr) {            
  466.                 tempUserData = myZoneBDS.userBytes;
  467.                 BlockMove((Ptr) &tempUserData, (Ptr) &DontGetMoreZones, 1); /* the highbyte will be nonzero if its the last packet of zones */
  468.                 BlockMove((Ptr)&tempUserData + 2, (Ptr) &NumZonesGot, 2);
  469.  
  470.                 addToUnpackedBuffer(myZoneBDS.buffPtr, returnBuffer, NumZonesGot, totalZones);    
  471.                 
  472.                 totalZones += NumZonesGot;
  473.                 }
  474.             }
  475.         
  476.         SetZoneCells(returnBuffer, totalZones);
  477.  
  478.         DisposPtr(theBufferPtr);
  479.         DisposPtr(returnBuffer);
  480.         }
  481.     
  482. }
  483.  
  484. /* 
  485.  *    zonesPresent is used to determine whether zones are present by checking the 
  486.  *    existence of a router.  In previous releases, we use to check that the
  487.  *    network number was non-zero.  Under ARA, the network number could be zero
  488.  *    however, the bridge node ID might not be.  This correction was implemented
  489.  *  by Pete Lovell, GE Information Services
  490.  */
  491. Boolean zonesPresent() 
  492. {
  493.     short         theBridgeNode = 0;
  494.     short        theBridgeNet = 0;
  495.     short        node;
  496.     OSErr        err;
  497.  
  498.     err = GetNodeAddress(&node, &theBridgeNet);
  499.     /* 
  500.      * On an extended network, this node ID is simply a flag.  Use _GetAppletalkInfo to get the
  501.      * real 24 bit address of the last router heard from.
  502.      */
  503.     theBridgeNode = GetBridgeAddress();
  504.     
  505.     if (theBridgeNode != 0)
  506.     {
  507.         gTheBridgeAddress.aNet = theBridgeNet;
  508.         gTheBridgeAddress.aNode = theBridgeNode;
  509.         gTheBridgeAddress.aSocket = kBridgeSocket;
  510.         return true;
  511.     }
  512.     else
  513.         return false;
  514. }
  515.  
  516.     
  517. void setItemString(DialogPtr whichDialog, short whichItem, Str255 str)
  518. {
  519.     Rect         r;
  520.     short         kind;
  521.     Handle         h;
  522.     
  523.     GetDItem(whichDialog, whichItem, &kind, &h, &r);
  524.     SetIText(h, str);
  525. }
  526.      
  527.  
  528. /* 
  529.  *    getTheZoneList is used to call the appropriate method to get the
  530.  *    zone list - assuming that zones are present.
  531.  */
  532. void getTheZoneList()
  533. {
  534.     if (zonesPresent()) {
  535.  
  536.         /*
  537.          * if AppleTalk Phase 2 is present (>= v53) then use new call
  538.          */
  539.         if(gHasPhase2)
  540.             doGetZoneListPhs2();
  541.         else
  542.             doGetZoneListPrePh2();
  543.         }
  544.     else { 
  545.         /* 
  546.          *    no zones.  inform user of this. 
  547.          */
  548.         tellUserNoZones();
  549.         }
  550. }
  551.  
  552.  
  553. void processListUpdate()
  554. {
  555.     Str255    tempStr, errorStr;
  556.     
  557.     if(gPBLkUP->myMPP.MPPioResult >= noErr) {
  558.         NumToString((long) gPBLkUP->myMPP.NBPnumGotten, tempStr);
  559.         Pstrcat(tempStr, "\p items");
  560.     
  561.         SetObjectTypeCells(gBuffPtr, gPBLkUP->myMPP.NBPnumGotten);
  562.         }
  563.     else {
  564.         NumToString((long) gPBLkUP->myMPP.MPPioResult, errorStr);
  565.         tempStr[0] = 0;
  566.         Pstrcat(tempStr, "\pError ID = ");
  567.         Pstrcat(tempStr, errorStr);
  568.         }
  569.     
  570.     gUpdateListFlag = false;
  571.     gLookupFinished = true;
  572.  
  573.     /* nil out specified text in dialog box since we're done looking */
  574.     ParamText("\p", "\p", "\p", "\p");        
  575.  
  576.     setItemString(gMyDialog, (short) kObjectCountID, tempStr);
  577.  
  578.     invalidateItem(kProgressID);
  579.     invalidateItem(kObjectCountID);
  580. }
  581.     
  582.  
  583. /* 
  584.  *    myCompletionRoutine is called to set a global flag which is 
  585.  *    inspected each time through the event loop.  The routine is
  586.  *    used by the asynch lookup call.  When the lookup completes,
  587.  *    the global flag is set telling the program to process the 
  588.  *    lookup replies - sort them per specified order.  For PowerPC
  589.  *    there is no need to set the A5 world as the OS does it for you.
  590.  */
  591.  
  592. #ifdef powerc
  593. void myCompletionRoutine(ParamBlockRec *paramBlock)
  594. {    
  595.     gUpdateListFlag = true;
  596. }
  597. #else
  598. void myCompletionRoutine(ParamBlockRec *paramBlock)
  599. {
  600.     saveThatA5();
  601.     gUpdateListFlag = true;
  602.     restoreThatA5();
  603. }
  604. #endif
  605.     
  606. char giveMeItemValue(short whichItem)
  607.  {
  608.     Rect         r;
  609.     short         kind;
  610.     Handle         h;
  611.     Str255        str;
  612.     long         value;
  613.     
  614.     GetDItem(gLookupDialog, whichItem, &kind, &h, &r);
  615.     GetIText(h, str);
  616.     StringToNum(str, &value);
  617.     
  618.     if(value>255) {
  619.         value = 255L;
  620.         SetIText(h, "\p255");
  621.         }
  622.     else if(value<0) {
  623.         value = 0L;
  624.         SetIText(h, "\p0");
  625.         }
  626.     return (short)value;
  627. }
  628.      
  629. void giveMeItemString(short whichItem, Str255 str)
  630. {
  631.     Rect         r;
  632.     short         kind;
  633.     Handle         h;
  634.     
  635.     GetDItem(gLookupDialog, whichItem, &kind, &h, &r);
  636.     GetIText(h, str);
  637. }
  638.      
  639. /* 
  640.  *    getTypesNamesInZone is called to initiate the NBP lookup
  641.  *    request.
  642.  *    used by the asynch lookup call.  When the lookup completes,
  643.  *    the global flag is set telling the program to process the 
  644.  *    lookup replies - sort them per specified order.  For PowerPC
  645.  *    there is no need to set the A5 world as the OS does it for you.
  646.  */
  647. void getTypesNamesInZone(char *NBPZone)
  648. {
  649.     OSErr                 resultCode;
  650.     Str255                 NBPObject, NBPType;
  651.     Str255                tempText;
  652.     Str32                noZoneName = "\pNo zones <*>.";
  653.     Str32                localZone = "\pthe local zone";
  654.     Boolean                localFlag = false;
  655.     static MPPCompletionUPP    gMyCompletionRoutineUPP = nil;
  656.     
  657.     if (gMyCompletionRoutineUPP==nil)
  658.         gMyCompletionRoutineUPP = NewMPPCompletionProc(myCompletionRoutine);
  659.     
  660.     /*myVBLSpinInstall();*/
  661.     
  662.     if (((dmzEntryPtr) *(gATQEntry.globs))->atalkActive == false)  // ATalk not active.
  663.         return;    
  664.     
  665.     /*
  666.      * Check whether there are no zones in the zone list
  667.      */
  668.     if (PStrComp(noZoneName, (unsigned char *)gNameGlob)) {
  669.         gNameGlob[0] = 1;
  670.         gNameGlob[1] = '*';
  671.         localFlag = true;
  672.     }
  673.     
  674.     BlockMove(NBPZone, &gNameGlob[0], 33L);
  675.  
  676.     /* 
  677.      *    oh dang... there may be an NBPLookup already pending.  Kill It first. 
  678.      */
  679.     killLookups();
  680.     
  681.     giveMeItemString(kObjectItem, NBPObject);
  682.     giveMeItemString(kTypeItem, NBPType);
  683.     NBPSetEntity((Ptr)&gLookupNTE.nt.entityData[0], (Ptr)NBPObject, (Ptr)NBPType, (Ptr)NBPZone);
  684.  
  685.     gPBLkUP->myA5 = (long)LMGetCurrentA5();    /* get the Current A5 */
  686.  
  687.     gLookupFinished = false;
  688.  
  689.     gPBLkUP->myMPP.MPPioCompletion = gMyCompletionRoutineUPP;
  690.     gPBLkUP->myMPP.NBPinterval = giveMeItemValue(kIntervalItem);
  691.     gPBLkUP->myMPP.NBPcount = giveMeItemValue(kCountItem);
  692.     gPBLkUP->myMPP.NBPentityPtr = (Ptr)&gLookupNTE.nt.entityData;
  693.     gPBLkUP->myMPP.NBPretBuffSize =  kLookupBufSize;
  694.     gPBLkUP->myMPP.NBPretBuffPtr = (Ptr) gBuffPtr;
  695.     gPBLkUP->myMPP.NBPmaxToGet =  255;        /* max zones for phase II internet */
  696.  
  697.     resultCode = PLookupName((MPPParamBlock *) &gPBLkUP->myMPP, true);
  698.     if (resultCode == 0)    
  699.         gLookupFinished = true;    
  700.     
  701.     /* 
  702.      * inform the user of what we are doing 
  703.      *     and zero out current entity count.
  704.      */
  705.     tempText[0] = 0;
  706.     if (localFlag)
  707.         Pstrcat(tempText, localZone);
  708.     else
  709.         Pstrcat(tempText, (unsigned char *)NBPZone);
  710.         
  711.     Pstrcat(tempText, "\p…");
  712.     ParamText("\p", "\p", "\plooking in:", tempText);        
  713.  
  714.     tempText[0] = 0;
  715.     setItemString(gMyDialog, (short) kObjectCountID, tempText);
  716.  
  717.     invalidateItem(kProgressID);
  718.     invalidateItem(kObjectCountID);
  719. }
  720.  
  721.  
  722. /* 
  723.  *    GetMyZone function
  724.  */
  725. void doGetMyZonePhs2()
  726. {
  727.     XCallParam    xpb;
  728.     OSErr        resultCode;
  729.     char        myZoneNameBuffer[33];
  730.     short        refNum;
  731.     
  732.     resultCode = OpenDriver("\p.XPP", &refNum);
  733.  
  734.     xpb.ioRefNum = refNum;
  735.     xpb.csCode = xCall;
  736.     xpb.xppSubCode = zipGetMyZone;
  737.     xpb.zipBuffPtr = (Ptr) &myZoneNameBuffer;
  738.     xpb.zipInfoField[0] = 0;    /* ALWAYS 0 */
  739.     resultCode = PBControl((ParmBlkPtr) &xpb, false);
  740. }
  741.  
  742. void doGetLocalZonesPhs2()
  743. {
  744.     XCallParam    xpb;
  745.     OSErr        resultCode = 0;
  746.     Ptr            returnBuffer, theBufferPtr;
  747.     short        refNum;
  748.     short        totalZones = 0;
  749.     
  750.     resultCode = OpenDriver("\p.XPP", &refNum);
  751.  
  752.     returnBuffer = NewPtr(33L*255L); /* size of maxstring size * 255 zones */
  753.     
  754.     theBufferPtr = NewPtr(578); /* size of BDS */
  755.     if(MemError()==noErr) {
  756.  
  757.         xpb.zipInfoField[0] = 0;    /* ALWAYS 0 on first call.  has state info on subsequent calls */
  758.         xpb.zipLastFlag = 0;
  759.  
  760.         xpb.ioRefNum = refNum;
  761.         xpb.csCode = xCall;
  762.         xpb.xppSubCode = zipGetLocalZones;
  763.         xpb.xppTimeout = 3;
  764.         xpb.xppRetry = 4;
  765.         xpb.zipBuffPtr = (Ptr) theBufferPtr;
  766.  
  767.         while(xpb.zipLastFlag == 0 && resultCode == 0) {
  768.  
  769.             resultCode = PBControl((ParmBlkPtr) &xpb, false);
  770.  
  771.             if(resultCode == noErr) {            
  772.                 addToUnpackedBuffer(theBufferPtr, returnBuffer, xpb.zipNumZones, totalZones);            
  773.                 totalZones += xpb.zipNumZones;
  774.                 }
  775.             }
  776.         
  777.         if(resultCode == noErr)     
  778.             SetZoneCells(returnBuffer, totalZones);
  779.  
  780.         DisposPtr(theBufferPtr);
  781.         DisposPtr(returnBuffer);
  782.         }
  783. }
  784.  
  785. /*
  786.  *    When AppleTalk Phase 2 is present, things go a bit easier.
  787.  */
  788. void doGetZoneListPhs2()
  789. {
  790.     XCallParam    xpb;
  791.     OSErr        resultCode = 0;
  792.     Ptr            returnBuffer, theBufferPtr;
  793.     short        refNum;
  794.     short        totalZones = 0;
  795.         
  796.     resultCode = OpenDriver("\p.XPP", &refNum);
  797.  
  798.     returnBuffer = NewPtr(33*255); /* size of maxstring size * 255 zones */
  799.     
  800.     theBufferPtr = NewPtr(578); /* size of BDS */
  801.     
  802.     if(MemError()==noErr) {
  803.         xpb.zipInfoField[0] = 0;    /* ALWAYS 0 on first call.  has state info on subsequent calls */
  804.         xpb.zipInfoField[1] = 0;    /* ALWAYS 0 on first call.  has state info on subsequent calls */
  805.         xpb.zipLastFlag = 0;
  806.         
  807.         xpb.ioRefNum = refNum;
  808.         xpb.csCode = xCall;
  809.         xpb.xppSubCode = zipGetZoneList;
  810.         xpb.xppTimeout = 3;
  811.         xpb.xppRetry = 4;
  812.         xpb.zipBuffPtr = (Ptr) theBufferPtr;
  813.  
  814.         while(xpb.zipLastFlag == 0 && resultCode == 0) {
  815.             resultCode = PBControl((ParmBlkPtr) &xpb, false);
  816.  
  817.             if(resultCode == noErr) {            
  818.                 addToUnpackedBuffer(theBufferPtr, returnBuffer, xpb.zipNumZones, totalZones);            
  819.                 totalZones += xpb.zipNumZones;
  820.                 }
  821.             }
  822.         /*
  823.          *    If all went well, add zone names to our list.
  824.          */
  825.          if(resultCode == noErr)     
  826.             SetZoneCells(returnBuffer, totalZones);
  827.  
  828.         /*
  829.          *    Dispose of memory we allocated.
  830.          */
  831.         DisposPtr(theBufferPtr);
  832.         DisposPtr(returnBuffer);
  833.         }
  834. }
  835.  
  836. /*
  837.  *    setupEchoDialog displays the echo packet test results having
  838.  *  processed the return packet.  This dialog displays the results
  839.  *  in terms of hop count to reach the object and seconds required to
  840.  *  "ping" the object.  If an error occurred, it is displayed instead
  841.  */
  842. void setupEchoDialog(DialogPtr echoDialog, myNetworkEntity *myEnt)
  843. {
  844.     short            kind;
  845.     Handle            h;
  846.     Rect            r;
  847.     Str32            noZoneName = "\pNo zones <*>.";
  848.     Str32            localZone = "\plocal zone";
  849.     Boolean            localFlag = false;
  850.     static UserItemUPP    gAboutOKFrameUPP = nil;
  851.     
  852.     if (gAboutOKFrameUPP==nil)
  853.         gAboutOKFrameUPP = NewUserItemProc(aboutDialogOKFrame);
  854.  
  855.     GetDItem(echoDialog, 10, &kind, &h, &r);
  856.     SetIText(h, (ConstStr255Param)myEnt->object);
  857.  
  858.     GetDItem(echoDialog, 11, &kind, &h, &r);
  859.     SetIText(h, (ConstStr255Param)myEnt->type);
  860.  
  861.     GetDItem(echoDialog, 12, &kind, &h, &r);
  862.     if (PStrComp(noZoneName, (unsigned char *)gNameGlob)) 
  863.         SetIText(h, localZone);
  864.     else
  865.         SetIText(h, (ConstStr255Param)gNameGlob);
  866.  
  867.     /* 
  868.      *    set up the userItem proc for the "OK" button outline 
  869.      */
  870.     GetDItem(echoDialog, 13, &kind, &h, &r);
  871.     SetDItem(echoDialog, 13, userItem, (Handle) gAboutOKFrameUPP, &r);
  872. }
  873.  
  874.  
  875. /*
  876.  *    doEcho is called when the user double clicks on some item indicating
  877.  *  to send an echo packet to the echo socket on the node of that item.
  878.  *  Note all of the preparation which is performed in order to "ping" the
  879.  *  object.  Note that the socket listener code has been implemented as 
  880.  *  a code resource so that for PowerPC we can make a mixed mode call to it.
  881.  
  882.  */
  883. void doEcho(myNetworkEntity    *myEnt)
  884. {
  885.     MPPParamBlock     myMPP;
  886.     OSErr            err;
  887.     Boolean            gotEcho = false;
  888.     WDSElement        myWDS[3];    /* minimum of 3 WDS elements in a Write Data Structure */
  889.     Ptr                gHdrPtr;
  890.     Ptr                myBuffer;
  891.     long            myTicks, myWaitTicks, startTicks, stopTicks;
  892.     unsigned char    myHops;
  893.     DialogPtr        echoDialog;
  894.     Str255            str;
  895.     short            kind;
  896.     Handle            h;
  897.     Rect            r;
  898.     short            itemHit;
  899.     AddrBlock         destAddress;
  900.     long            tempL;
  901.     GrafPtr            savedPort;
  902.     PacketPtr        bufPtr;
  903.         
  904.     GetPort(&savedPort);
  905.  
  906. #ifndef powerc    
  907.     MYVBLSPININSTALL();
  908. #endif
  909.  
  910.     StringToNum((StringPtr) myEnt->net, (long *) &tempL);
  911.     destAddress.aNet = tempL;
  912.     StringToNum((StringPtr) myEnt->node, (long *) &tempL);
  913.     destAddress.aNode = tempL;
  914.     StringToNum((StringPtr) myEnt->socket, (long *) &tempL);
  915.     destAddress.aSocket = tempL;
  916.  
  917.     echoDialog = GetNewDialog(131, 0L, (WindowPtr) -1L);
  918.     SetPort(echoDialog);
  919.     
  920.     TextFont(geneva);
  921.     TextSize(9);
  922.     
  923.     setupEchoDialog(echoDialog, myEnt);
  924.     
  925.     myMPP.DDPlistener = (DDPSocketListenerUPP) *gSockCodeHndl;
  926.  
  927.     myMPP.DDPsocket = 0;
  928.     err = POpenSkt(&myMPP, false);
  929.     
  930.     gHdrPtr = NewPtr(17);                 /* max header size */
  931.     
  932.     destAddress.aSocket = 4;             /* Echoer socket */
  933.     myBuffer = NewPtr(ddpMaxData);
  934.     *myBuffer = 1;                        /* tell their Echoer we want a reply with a 1 in the first byte */
  935.     
  936.     BuildDDPwds((Ptr) &myWDS, gHdrPtr, myBuffer, destAddress, kEchoSocket, ddpMaxData);
  937.     
  938.     myMPP.DDPchecksumFlag = true;
  939.     myMPP.DDPwdsPointer = (Ptr) &myWDS;
  940.     
  941.     startTicks = TickCount();            /* start the timer! */
  942.     
  943.     err = PWriteDDP(&myMPP, false);
  944.  
  945.     myWaitTicks = TickCount() + 600L;    /* wait 10 seconds for reply */
  946.     
  947.     while(myWaitTicks > TickCount() && !gUsedQ.qHead)  {}
  948.     
  949.     if(gUsedQ.qHead) {
  950.         bufPtr = (PacketPtr)gUsedQ.qHead;    /* get the packet ptr */
  951.                         /* we could check the DDP type in the buffer_type field
  952.                          * but we leave it as an exercise to the reader.  
  953.                          * Note that the way the gUsedQ is structured so that 
  954.                          * we could check whether the packet is for us, or for 
  955.                          * some other process which utilizes the same listener.  
  956.                          * In the next step we dequeue the packet so that it 
  957.                          * doesn't get overwritten */
  958.         if (Dequeue((QElemPtr)gUsedQ.qHead, &gUsedQ) == noErr) {
  959.             if (bufPtr->buffer_CheckSum != noErr)
  960.             {
  961.                 GetDItem(echoDialog, 6, &kind, &h, &r);
  962.                 SetIText(h, "\pWah…Checksum error occurred");
  963.             }
  964.             else
  965.             {
  966.                 stopTicks = bufPtr->buffer_Ticks;
  967.                 myTicks = stopTicks - startTicks;
  968.         
  969.                 GetDItem(echoDialog, 4, &kind, &h, &r);
  970.                 myHops = bufPtr->buffer_Hops;
  971.                 NumToString((long) myHops, (void *) &str);
  972.                 SetIText(h, str);
  973.             
  974.                 GetDItem(echoDialog, 5, &kind, &h, &r);
  975.                 NumToString(myTicks, (void *) &str);
  976.                 SetIText(h, str);
  977.             }
  978.                                         /* requeue the packet buffer for use. */
  979.             Enqueue((QElemPtr)bufPtr, &gFreeQ);
  980.         }
  981.         else {
  982.             GetDItem(echoDialog, 6, &kind, &h, &r);
  983.             SetIText(h, "\pWah… packet Dequeue error occured");
  984.         }
  985.     }
  986.     else {
  987.         GetDItem(echoDialog, 6, &kind, &h, &r);
  988.         SetIText(h, "\pWah… no echo reply received!");
  989.     }
  990.     /* clean up memory allocations */
  991.     DisposPtr(gHdrPtr);
  992.     DisposPtr(myBuffer);
  993.     err = PCloseSkt(&myMPP, false);    
  994.     
  995.     /* report the results */
  996.     centerDialog((WindowPtr) echoDialog);
  997.  
  998. #ifndef powerc
  999.     STOPANDREMOVESPINNINGCURSOR();
  1000. #endif
  1001.  
  1002.     InitCursor();
  1003.     ShowWindow(echoDialog);
  1004.     
  1005.     ModalDialog(0L, &itemHit);
  1006.     DisposDialog(echoDialog);
  1007.     
  1008.     SetPort(savedPort);
  1009. }
  1010.  
  1011.  
  1012. /*
  1013.  *    Here's our AppleTalk Transition Queue handler - we just want
  1014.  *  to know if the user shuts down AppleTalk, or changes connections
  1015.  *  and do the right thing like deregister our NBP name.  On entry 
  1016.  *  the current A5 world gets saved under 68K and set to that of
  1017.  *  our application.  We can then make calls to the program and
  1018.  *  use program globals.
  1019.  */
  1020.  
  1021. long ATalkTransQueue(long selector, myATQEntry *q, void *p)
  1022. {
  1023. #pragma unused (p)
  1024.     long                returnVal = 0; /* return 0 for unrecognized events */
  1025.     dmzEntryPtr            dmzPtr;
  1026.     long                a5Save;
  1027.         
  1028.     //DebugStr("\pEntering ATQ");
  1029.  
  1030. #ifndef    powerc
  1031.     /* set a5 to that for the app */
  1032.     a5Save = SetA5(q->myA5);
  1033. #endif
  1034.     /*
  1035.      * This is the dispatch part of the routine. We'll check the selector passed into
  1036.      * the task; its location is 4 bytes off the stack (selector).
  1037.      */
  1038.  
  1039.     dmzPtr = (dmzEntryPtr)*(q->globs);
  1040.     switch(selector) {
  1041.         case ATTransOpen:
  1042.             /*
  1043.              *  Someone has opened the .MPP driver. Set Flag to re-initialize AppleTalk portion of pgm
  1044.              */
  1045.              
  1046.             dmzPtr->atalkStatusChanged = true;
  1047.             dmzPtr->atalkActive = true;            
  1048.             break;
  1049.             
  1050.         case ATTransClose:
  1051.             /*
  1052.              *  .MPP is going to shut down no matter what we do.  Call Cleanup routine
  1053.              */
  1054.  
  1055.             removeMyNameAndSocket();
  1056.             
  1057.             dmzPtr->atalkStatusChanged = true;
  1058.             dmzPtr->atalkActive = false;            
  1059.             break;
  1060.  
  1061.  
  1062.         case ATTransClosePrep:
  1063.             /*
  1064.              *  .MPP is asking whether it can shut down.  
  1065.              */
  1066.  
  1067.             break;
  1068.             
  1069.     } /* end of switch */
  1070.     
  1071.     /* 
  1072.      *    return value in register D0 
  1073.      */
  1074. #ifndef    powerc
  1075.     SetA5(a5Save);
  1076. #endif
  1077.     return returnVal;
  1078. }
  1079.  
  1080. /*
  1081.  *    This routine loads the socket listener code and initializes the buffers to 
  1082.  *  be used by the socket listener code. A check is made to determine whether VM
  1083.  *  is active and to hold the memory associated with buffers that might be 
  1084.  *  critical to the operation of the socket listener.  We load the socket 
  1085.  *  socket listener code resource and lock it in memory.
  1086.  */
  1087.  
  1088. OSErr InitEchoBuffers(void)
  1089. {
  1090.     OSErr            err = noErr;
  1091.     short            i;
  1092.     Size            listenerSize;
  1093.     
  1094.     /* check whether the buffers have already been init'd */
  1095.  
  1096.     if (!(gATalkFlags & (1 << kSocketBuffsInitd))) {
  1097.         /* set up the free and used queues */
  1098.         gFreeQ.qFlags = 0;
  1099.         gFreeQ.qHead = nil;
  1100.         gFreeQ.qTail = nil;
  1101.         
  1102.         gUsedQ.qFlags = 0;
  1103.         gUsedQ.qHead = nil;
  1104.         gUsedQ.qTail = nil;
  1105.         
  1106.         /* enqueue the packet buffer records to the free queue */
  1107.         for (i=0; i<kNumBuffers; i++, gFreeQ.qFlags ++)
  1108.             Enqueue((QElemPtr)&gBuffers[i], &gFreeQ);
  1109.         
  1110.         /* show that the buffers have been init'd */
  1111.         gATalkFlags |= (1 << kSocketBuffsInitd);
  1112.         
  1113.         /* check whether VM is on and hold the packet buffers */
  1114.         if (gATalkFlags & (1 << kVMActive)) {
  1115.  
  1116.             err = HoldMemory(&gBuffers, sizeof(gBuffers));
  1117.             if (err == noErr)  {
  1118.                 /* mark queue structures for hold */
  1119.                 HoldMemory(&gFreeQ, sizeof(QHdr));
  1120.                 HoldMemory(&gUsedQ, sizeof(QHdr));
  1121.                 /* set the global ATalkFlags to reflect the held memory */
  1122.                 gATalkFlags |= (1 << kSocketBuffsHeld);
  1123.             }
  1124.         }
  1125.                 
  1126.         /*********** get socket listener code **********/
  1127.         if (gSockCodeHndl == nil)
  1128.         {
  1129.             gSockCodeHndl = Get1Resource('Sock',128);
  1130.             if (gSockCodeHndl==nil)
  1131.                 return (resNotFound);
  1132.             MoveHHi(gSockCodeHndl);
  1133.             HLock(gSockCodeHndl);
  1134.             
  1135.             /* tell the socket listener about the 2 queues */
  1136.             err = CallInitSktListenerProc(((InitSktListenerProcPtr)((long) *gSockCodeHndl + 2)), &gFreeQ, &gUsedQ);
  1137.  
  1138.         /*********** end get socket listener code **********/
  1139.  
  1140.             if (err == noErr) {
  1141.                 if (gATalkFlags & (1 << kVMActive)) 
  1142.                 {
  1143.                     listenerSize = GetHandleSize(gSockCodeHndl);
  1144.     
  1145.                     err = HoldMemory(*gSockCodeHndl, listenerSize);
  1146.                     if (err == noErr)
  1147.                         gATalkFlags |= (1 << kListenerHeld);
  1148.                 }
  1149.             }
  1150.             if (err)
  1151.                 BigBadError("\pSocket listener init failed - aborting program");
  1152.                 /* I guess we could fail the use of the socket listener
  1153.                  * instead of aborting the program however, that is left as an
  1154.                  * exercise to the user
  1155.                  */
  1156.         }
  1157.         
  1158.     }
  1159.     return(err);
  1160.  
  1161. }
  1162.  
  1163. Boolean GestaltAvailable(void)
  1164. {
  1165.     return (TrapAvailable(_Gestalt));
  1166. }
  1167.  
  1168.  
  1169. short AppleTalkVersion(void)
  1170. {
  1171.     short         versionRequested = 1; /* version of SysEnvRec */
  1172.     short        refNum;
  1173.     long        attrib;
  1174.     short        atlkVer;
  1175.  
  1176.     atlkVer = 0;    /* default to no AppleTalk */
  1177.     if (GestaltAvailable())            /* check whether Gestalt is available */
  1178.     {
  1179.         if (Gestalt('atkv', &attrib) == noErr)    /* check the atkv selector which */
  1180.         {                                        /* return ATalk version regardless whether */
  1181.                                                 /* ATalk is on or off */
  1182.             atlkVer = attrib >> 24;
  1183.         }
  1184.         else if (OpenDriver("\p.MPP", &refNum) == noErr)    /* open, then check the 'atlk' */
  1185.         {                                        /* selector to get ATalk version */
  1186.             if (Gestalt(gestaltAppleTalkVersion, &attrib) == noErr)
  1187.                 atlkVer = attrib & 0x000000FF;
  1188.         }
  1189.     }
  1190.     return atlkVer;
  1191. }
  1192.  
  1193.  
  1194. Boolean LAPMgrExists(void)
  1195. {    
  1196.     return (AppleTalkVersion() >= 53);
  1197. }
  1198.